package com.wxapp.common.core.annotation.resolver;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.wxapp.common.constant.enums.StrategyEnum;
import com.wxapp.common.core.annotation.Sensitive;
import com.wxapp.common.core.filter.except.ThrowMyException;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.util.Collections;

/**
 * 脱敏字段序列化器
 */
@RequiredArgsConstructor
public class SensitiveResolver extends JsonSerializer<String> implements ContextualSerializer {
    private final Sensitive sensitive;
    @SneakyThrows
    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (StringUtils.isBlank(value)) {
            gen.writeString(value);
            return;
        }
        if (sensitive != null) {
            StrategyEnum strategyEnum = sensitive.strategy();
            String replaceString = sensitive.replaceStr();
            gen.writeString(getValue(value, strategyEnum, sensitive.startSub(), sensitive.endSub(), replaceString));
        } else {
            gen.writeString(value);
        }

    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) {
        Sensitive annotation = property.getAnnotation(Sensitive.class);

        if (annotation != null) {
            return new SensitiveResolver(annotation);
        }
        return this;
    }

    private String getValue(String rawStr, StrategyEnum strategyEnum, int startSub, int endSub, String replaceString) throws ThrowMyException {
        switch (strategyEnum) {
            case ALL:
                return rawStr.replaceAll("[\\s\\S]", replaceString);
            case LEFT:
            case RIGHT:
            case CENTER:
                return replaceByLength(rawStr, startSub, endSub, replaceString);
            default:
                throw new ThrowMyException("Illegal Sensitive Strategy");
        }
    }

    private String replaceByLength(String rawStr, int startSub, int endSub, String replaceString) {
        if (StringUtils.isBlank(rawStr)) {
            return rawStr;
        }
        String[] split = rawStr.split(rawStr.substring(startSub - 1, endSub));
        var join = String.join("", Collections.nCopies(endSub - startSub, replaceString));
        if (split.length > 2) {
            int lenth = 0;
            int sub = 0;
            while (lenth != 12 && sub < split.length) {
                if (sub == 0) {
                    lenth = lenth + split[sub].length() + 1;
                } else {
                    lenth = lenth + split[sub].length() + 5;
                }
                sub++;
            }
            split[sub - 1] = split[sub - 1] + join;
            return String.join("", split);
        }
        return String.join(join, split);
    }
}